<?php
# 定义错误反馈类型
error_reporting(E_ALL | E_STRICT);
ini_set('display_errors', '1');

# 定义app根目录
define('APP_DIR', dirname(__FILE__));

defined('IN_CLI') || define('IN_CLI', PHP_SAPI === 'cli');

require_once APP_DIR . '/view.class.php';
require_once APP_DIR . '/sql.class.php';
require_once APP_DIR . '/inspect.class.php';
require_once APP_DIR . '/route.class.php';
require_once APP_DIR . '/unirest.class.php';

class App
{
	const TRACE = 1;
    const DEBUG = 2;
    const INFO  = 3;
    const WARN  = 4;
    const ERROR = 5;
    const FATAL = 6;

    const AS_KEY = 'as';
    const WIDGET_KEY = 'widget';

    static $logger = null;

    static function log($level, $content)
    {
    	if (is_callable(self::$logger))
    	{
    		call_user_func_array(self::$logger, array($level, $content));
    	}
    }

	static function execute()
	{
		static $not_started = true;
        if ($not_started)
        {
        	error_reporting(E_ALL | E_STRICT);
        	date_default_timezone_set('Asia/Shanghai');
        	session_start();
            $not_started = false;
            header("Content-Type: text/html;charset=utf-8");

            Route::init();
        }

		$app = $_GET[ROUTE_APP_KEY];
		$f = APP_DIR . "/app/{$app}/_init_.php"; 
		if ( is_readable( $f ) )
		{
			require_once ($f);			
			$func = "{$app}_init";
			if ( is_callable($func) )
			{
				$func();
			}					
		}

		$q = $_GET[ROUTE_Q_KEY];
		if ( $_GET[ROUTE_SET_KEY] == ROUTE_HTML_INDEX || $_GET[ROUTE_SET_KEY] == ROUTE_HTML_APP )
		{
			$as = self::getAs();

			if ( !empty($as[App::WIDGET_KEY]) )
			{
				$as[App::WIDGET_KEY] = explode('|', trim($as[App::WIDGET_KEY],'+ \t\r\n\0\x0B\/|'));
				foreach ( $as[App::WIDGET_KEY] as $widget )
				{
					$widget = preg_replace('/[^a-z0-9\.]/', '', $widget);
					if ( empty($widget) ) continue;

					$wdata = self::widget($widget, $app); 
					$name = 'wg_' . str_replace('.', '_', $widget);
					$as[ $name ] = $wdata;
				}
			}

			$as['_root_'] = Route::get_request_dir();
			$as['_static_'] = $as['_root_'] . 'static';

			$view = new View(APP_DIR . "/app/{$app}", $q, $as);
			$viewfile = $view->view_filename($q);
			if ( !is_readable( $viewfile ) )
			{
				die( sprintf('cannot load view: (%s) in [%s]', $q, $app));
			}
			return $view->execute();

		}
		else
		{			
			return self::__sf($q, $app);
		}

	}

	static function getAs()
	{
		return empty($_GET[App::AS_KEY]) || !is_array( $_GET[App::AS_KEY] ) ? 
			array() : $_GET[App::AS_KEY];
	}

	static function __url($route_key, $params, $anchor)
	{
		$as = empty($params[App::AS_KEY]) ? array() : $params[App::AS_KEY];

		unset( $as[ROUTE_APP_KEY] );
		unset( $as[ROUTE_Q_KEY] );
		unset( $as[ROUTE_SET_KEY] );
		
		if (!empty($as[App::WIDGET_KEY]) && is_array($as[App::WIDGET_KEY]))
		{
			$as[App::WIDGET_KEY] = implode('|',$as[App::WIDGET_KEY]);
		}
		else
		{
			unset( $as[App::WIDGET_KEY] );
		}

		if ( empty($as) ) {
			unset( $params[App::AS_KEY] );
		}
		else
		{
			$params[App::AS_KEY] = $as;
		}

		return Route::rewrite_url($route_key, $params) . (empty($anchor) ? '' : '#' . trim($anchor));
	}

	private static function __sf($q, $app)
	{
		$app = strtolower(trim($app));
		if ( empty($q) ) $q = ROUTE_DEFAULT_Q;
		$q = strtolower(trim($q));
		
		$f = APP_DIR . "/app/{$app}/_sf/" . str_replace('.', '/', $q) . '.php';

		if ( is_readable( $f ) )
		{
			require_once ($f);
			$sffunc = "{$app}_sf_". str_replace('.', '_', $q);
			if ( is_callable($sffunc) )
			{				
				$filter = "{$app}_filter";
				if ( is_callable($filter) )
				{
					# action 可从注释提取元信息扩展功能
					$reflect = "{$app}_sf_reflect";
					$bool = $filter($q,$sffunc,is_callable($reflect) ? $reflect($sffunc) : null);
					if (!$bool) die( sprintf('cannot pass filter: (%s) in [%s]', $q, $app));;
				}
				return $sffunc();
			}
		}
		die( sprintf('cannot load sf: (%s) in [%s]', $q, $app));
	}

	static function widget($name, $app=ROUTE_DEFAULT_APP)
	{
		$app = trim($app);
		$name = strtolower(trim($name));if (empty($app)||empty($name)) return '';
		
		$f = APP_DIR . "/app/{$app}/_widget/" . str_replace('.', '/', $name) . '.php';
		if ( is_readable($f) )
		{
			require_once ($f);
			$class = 'Wg' . ucfirst($app) . '_' . str_replace('.', '_', $name);
			if ( class_exists($class,false) )
			{
				$new = new $class();
				if ( is_callable( array($new, 'execute') ) )
				{
					return $new->execute();
				}
			}
		}
		return '';
	}

}

function url($route_key, $params=array(), $anchor='')
{
	return App::__url($route_key, $params, $anchor);
}

function url_params($app, $q, $widget=null, $as=null, $params=null)
{
	if ( !is_array($params) ) $params = array();
	$params[ROUTE_APP_KEY] = $app;
	$params[ROUTE_Q_KEY] = $q;
	$params[App::AS_KEY] = is_array($as) ? $as : array();

	if ( !empty($widget) ) $params[App::AS_KEY][App::WIDGET_KEY] = $widget;
	return $params;
}

function url_sfparams($app, $q, $params=null)
{
	return url_params($app, $q, null, null, $params);
}

function redirect($url, $delay =0)
{
    $delay = (int) $delay;
    if (headers_sent() || $delay > 0)
    {
        $out = '<html>
        <head>
        <meta http-equiv="refresh" content="%d;URL=%s" />
        </head>
        </html>';
        echo sprintf($out, $url, $delay);
    }
    else
    {
        header("Location: {$url}");
    }       
    exit;
}

function redirect301($url)
{
	header('HTTP/1.1 301 Moved Permanently');
	header("Location: {$url}");
	exit;
}

function is_windows()
{ 
	return 'win' === strtolower(substr(php_uname("s"), 0, 3));
}

function locale_str($str)
{
	if ( is_windows() )
	{
		$str = iconv("UTF-8", "GBK", $str);
	}
	return $str;
}

if (IN_CLI)
{
	function prety_printr($vars, $label = '', $return = false)
	{
		$content = print_r($vars,true);
		if ( $label != '' )
		{
			$content = "[$label]: " . $content;
		}
		$content = locale_str($content);

	    if ($return) { return $content; }
	    fwrite(STDOUT, $content . PHP_EOL);
	}
}
else
{
	function prety_printr($vars, $label = '', $return = false)
	{
		$content = "<pre>\n";
	    if ($label != '') {
	        $content .= "<strong>{$label} :</strong>\n";
	    }
	    $content .= htmlspecialchars(print_r($vars, true),ENT_COMPAT | ENT_IGNORE);
	    $content .= "\n</pre>\n";

	    if ($return) { return $content; }
	    echo $content;
	}
}



echo App::execute();